#include "ActionGetUserInfo.h"
#include "json.h"
#include "util.h"
#include "streamdata.h"
#include "agency_event_service.h"
#include "agencyeventmgr.h"
#include "9200_agency_event_api.pb.h"


static std::map<std::string,std::string> http_json_heads = {{"Content-Type","application/json"}};

static bool __init__ = ActionGetUserInfo::Init();

bool ActionGetUserInfo::Init()
{
    Ctx.msg_router.BindMsg(agency_event_api::AGENCY_EVENT_API_MSGID_USER_INFO_REQ, ActionGetUserInfo::Handle);
    AgencyEventService::Instance()->ListenOnAgencyEventGet(AgencyEventService::USERINFO, ActionGetUserInfo::OnAgencyEventGet);

    return true;
}

void ActionGetUserInfo::Handle(MsgData&& msg_data)
{
    agency_event_api::UserInfoReq req;
    agency_event_api::UserInfoResp resp;

    do {
        if (!req.ParseFromArray(msg_data.data.data(), msg_data.data.size()))
        {
            resp.set_errorcode(agency_event_api::ErrorCode::DataParseErr);
            log_error("parser agency_event_api::UserInfoReq failed");
            break;
        }
        log_debug("req:%s", req.ShortDebugString().c_str());

        stAgencyEvent* st_agencyevent = AgencyEventMgr::Instance()->Get(req.agency_id());
        if (st_agencyevent != nullptr)
        {
            Request(*st_agencyevent, msg_data.svtype, msg_data.svid, msg_data.uuid, req);
        }
        else
        {
            StreamData stream_data;
            StreamDataWriter writer(stream_data);
            writer.WriteShort(msg_data.svtype);
            writer.WriteInt(msg_data.svid);
            writer.WriteInt(msg_data.uuid);
            std::string str;
	        req.SerializeToString(&str);
            writer.WriteString(str);

            if (!AgencyEventService::Instance()->HandleGetAgencyEvent(req.agency_id(), std::move(stream_data.Data()), AgencyEventService::USERINFO))
            {
                resp.set_errorcode(agency_event_api::ErrorCode::AgencyGetErr);
                log_error("HandleGetAgencyEvent failed,agencyid:%u", req.agency_id());
                break;
            }
        }
        return;
    } while(false);

    if (resp.errorcode() != 0)
    {
        // 回包
        resp.set_uid(req.uid());
        resp.set_trans(req.trans());
        Ctx.host->MtSendtoOneSrv(agency_event_api::AGENCY_EVENT_API_MSGID_USER_INFO_RESP, &resp, msg_data.svtype, msg_data.svid, false, msg_data.uuid);
    }
}

void ActionGetUserInfo::OnAgencyEventGet(std::int32_t err_code, stAgencyEvent* agencyevent, std::string&& trans)
{
    StreamData stream_data(std::move(trans));
    StreamDataReader reader(stream_data);
    std::uint16_t svtype = reader.ReadShort();
    std::uint32_t svid = reader.ReadInt();
    std::uint32_t uuid = reader.ReadInt();
    std::string reqStr = reader.ReadString();
    agency_event_api::UserInfoReq req;
    agency_event_api::UserInfoResp resp;
    do
    {
        if (!req.ParseFromString(reqStr))
        {
            resp.set_errorcode(agency_event_api::ErrorCode::DataParseErr);
            log_error("parser agency_event_api::UserInfoReq failed");
            break;
        }
        if (err_code != 0)
        {
            resp.set_errorcode(agency_event_api::ErrorCode::AgencyGetErr);
            log_error("get agency info failed,agencyid:%u,err_code:%d", req.agency_id(), err_code);
            break;
        }
        if (agencyevent == nullptr)
        {
            resp.set_errorcode(agency_event_api::ErrorCode::AgencyGetErr);
            log_error("agency is nullptr,agencyid:%u,err_code:%d", req.agency_id(), err_code);
            break;
        }

    
        Request(*agencyevent, svtype, svid, uuid, req);
        return;
    } while(false);

    if (resp.errorcode() != 0)
    {
        // 回包
        resp.set_uid(req.uid());
        resp.set_trans(req.trans());
        Ctx.host->MtSendtoOneSrv(agency_event_api::AGENCY_EVENT_API_MSGID_USER_INFO_RESP, &resp, svtype, svid, false, uuid);
    }
}

void ActionGetUserInfo::Request(const stAgencyEvent& agencyevent, std::uint16_t svtype, std::uint32_t svid, std::uint32_t uuid,  const agency_event_api::UserInfoReq& UserInfoReq)
{
    agency_event_api::UserInfoResp resp;
    do
    {
        if (agencyevent.state != 1)
        {
            resp.set_errorcode(agency_event_api::ErrorCode::AccessLimitErr);
            log_error("agency state not valid, %s", agencyevent.ToString().c_str());
            break;
        }

        // if (agencyevent.gamelist.find(UserInfoReq.game()) == agencyevent.gamelist.end())
        // {
        //     resp.set_errorcode(agency_event_api::ErrorCode::GameLimitErr);
        //     log_error("game:%u not support, %s", UserInfoReq.game(), agencyevent.ToString().c_str());
        //     break;
        // }

        std::string req_id = GenTransId();
        std::uint64_t reqtime = CTools::GetUnixTime();
        //Json::Value usernameList_json;
        uint32_t agencyid = UserInfoReq.agency_id();

        Json::Value http_req;
        http_req["reqId"] = req_id;
        http_req["reqtime"] = Json::Int64(reqtime);
        http_req["username"] = UserInfoReq.username();

        std::string url = agencyevent.call_url + "/GetUserInfo";

        std::string json_string = CTools::ToStr(http_req);
        std::uint32_t event_id = 0;
        // 请求http网络
        if (!Ctx.msg_router.sendHttpPOST(url, json_string, http_json_heads, event_id) || (event_id == 0))
        {
            resp.set_errorcode(agency_event_api::ErrorCode::SendPostErr);
            log_error("net post failed,url:%s,param:%s", url.c_str(), json_string.c_str());
            break;
        }
        std::uint32_t uid = UserInfoReq.uid();
        // 添加回调监听
        std::int64_t currency_unit_multi = agencyevent.currency_unit_multi;

        auto req_copy = std::make_shared<agency_event_api::UserInfoReq>(UserInfoReq);
        Ctx.msg_router.AddCurlEvent(event_id, [svtype, svid, uuid,
            url=std::move(url), json_string= std::move(json_string), reqtime, req_copy, currency_unit_multi] (std::string& body, bool is_ok){
            agency_event_api::UserInfoResp resp;
            Json::Value http_resp;
            
            std::uint64_t resptime = CTools::GetUnixTime();

            log_info("url:%s,req:%s,resp:%s,reqtime:%llu,resptime:%llu", 
                url.c_str(), json_string.c_str(), body.c_str(), reqtime, resptime);

            do
            {
                // 网络错误
                if (!is_ok)
                {
                    resp.set_errorcode(agency_event_api::ErrorCode::RespTimeout);
                    log_error("time out,url:%s,param:%s", url.c_str(), json_string.c_str());
                    break;
                }
                
                // 解析返回格式
                if (!CTools::FromStr(http_resp, body))
                {
                    resp.set_errorcode(agency_event_api::ErrorCode::DataParseErr);
                    log_error("resp from json failed, body:%s ,url:%s,param:%s", body.c_str(), url.c_str(), json_string.c_str());
                    break;
                }
                if (!http_resp.isMember("errorCode") || !http_resp["errorCode"].isInt())
                {
                    resp.set_errorcode(agency_event_api::ErrorCode::InvaildParam);
                    log_error("response param invalid, body:%s ,url:%s,param:%s", body.c_str(), url.c_str(), json_string.c_str());
                    break;
                }
                
                if (!http_resp.isMember("totalrecharge") || !http_resp["totalrecharge"].isDouble()
                    || !http_resp.isMember("balance") || !http_resp["balance"].isDouble()
                    || !http_resp.isMember("deviceId") || !http_resp["deviceId"].isString()
                    || !http_resp.isMember("loginIp") || !http_resp["loginIp"].isString()
                    || !http_resp.isMember("regtime") || !http_resp["regtime"].isInt64()
                    || !http_resp.isMember("rechargecount") || !http_resp["rechargecount"].isInt()
                    )
                {
                    resp.set_errorcode(agency_event_api::ErrorCode::InvaildParam);
                    log_error("response param invalid, body:%s ,url:%s,param:%s", body.c_str(), url.c_str(), json_string.c_str());
                    break;
                }
                resp.set_totalrecharge(http_resp["totalrecharge"].asDouble() * currency_unit_multi);
                resp.set_device_id(http_resp["deviceId"].asString());
                resp.set_login_ip(http_resp["loginIp"].asString());
                resp.set_reg_time(http_resp["regtime"].asInt64());
                resp.set_rechargecount(http_resp["rechargecount"].asUInt());
                resp.set_balance(http_resp["balance"].asDouble() * currency_unit_multi);
                resp.set_nickname(http_resp["nickname"].asString());
            } while (false);
            
            // 回包
            resp.set_uid(req_copy->uid());
            resp.set_errorcode(http_resp["errorCode"].asInt());
            resp.set_trans(std::move(req_copy->trans()));
            log_debug("resp:%s http%s", resp.ShortDebugString().c_str(), CTools::ToStr(http_resp).c_str());
            Ctx.host->MtSendtoOneSrv(agency_event_api::AGENCY_EVENT_API_MSGID_USER_INFO_RESP, &resp, svtype, svid, false, uuid);
        });

        return;
    } while(false);

    if (resp.errorcode() != 0)
    {
        // 回包
        resp.set_uid(UserInfoReq.uid());
        resp.set_trans(UserInfoReq.trans());
        Ctx.host->MtSendtoOneSrv(agency_event_api::AGENCY_EVENT_API_MSGID_USER_INFO_RESP, &resp, svtype, svid, false, uuid);
    }
}
